/**
 * 
 */
package RC.structs;

import graph.Graph;
import graph.gviz.DotViewer;
import graph.gviz.DotViewer.DotViewerFrame;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import mdp.id.ADDHandler;
import mdp.id.RDDL2DD;
import mdp.id.RDDL2DD.DEBUG;
import mdp.id.RDDL2DD.ORDER;

/**
 * @author NR
 *
 * TODO
 */
public class DTree<D extends RDDL2DD> {
	public static final String	VIEWER_FILE	= "tmp_rddl_graphviz.dot";;
	public static final int DEFAULT_VIEWER_TEXT_LINES = 15;
	public static final int VIEWER_TEXT_HEIGHT = 20; // pixels
	
	private D _context;
	
	private int aCutSetWidth;
	private int contextWidth;
	private int cutsetWidth;
	
	private List<String> _elimOrder;
	
	
	
	public DTreeNode _root;
	protected Map<Integer, DTreeNode<D>>	_hmid2Node = new HashMap<Integer, DTreeNode<D>>();
	/**
	 * 
	 */
	public DTree(D context, Set<String> cptVars, List<String> elimOrder ) {
		_context = context;
		_elimOrder = elimOrder;
		
		ArrayList<DTreeNode> leafnodes = new ArrayList<DTreeNode>();
		
		//make leaf nodes
		for( String cptvar : cptVars ) {
			Integer id = context.toID(cptvar);
			int cpt = context.getDualDiagram(id, null);
//			if( !isExogenous(cpt) ) {
				DTreeNode leafNode = new DTreeNode<RDDL2DD>(context, cpt);
				leafnodes.add(leafNode);
				_hmid2Node.put(leafNode.id, leafNode);
//			}else {
//				System.out.println("Exogenous " + cptvar);
//			}
		}
		
		ArrayList<Integer> rews = _context.getRewards();
		for( Integer i : rews ) {
			DTreeNode leafNode = new DTreeNode<RDDL2DD>(context, i);
			leafnodes.add(leafNode);
			_hmid2Node.put(leafNode.id, leafNode);	
		}
		
		
		//compose leaf nodes
		for(String a : elimOrder ) {
			//go thru leaf nodes
			ArrayList<DTreeNode> merges = new ArrayList<DTreeNode>();
			
			for( int i = 0; i < leafnodes.size(); ++i ) {
				DTreeNode leaf = leafnodes.get(i);
				Set<String> vars = leaf.getVars();
				if( vars.contains(a) ) {
					merges.add(leaf);
				}
			}

			DTreeNode newOne = compose(Collections.unmodifiableList(merges));
			leafnodes.removeAll(merges);
			leafnodes.add(newOne);
			
			
			//remove two
			//merge them
			//put new one in
			//zzzzzzzzzzzzzzzzzz
		}
		
		while( leafnodes.size() != 1 ) {
			DTreeNode one = leafnodes.remove(0);
			DTreeNode other = leafnodes.remove(0);
			DTreeNode newOne = new DTreeNode<D>(context, one, other);
			_hmid2Node.put(newOne.id, newOne);
//			System.out.println("merging " + one.getLabel() + " " + other.getLabel());
			leafnodes.add(newOne);
		}
		
		if( leafnodes.size() != 1 ) {
			System.err.println("boo");
			System.exit(1);
		}
		_root = leafnodes.get(0);
		_root.getVars();
		try
		{
			ArrayList<Integer> ret = _root.seed(new HashSet<String>());
			cutsetWidth = ret.get(0);
			aCutSetWidth = ret.get(1);
			contextWidth = ret.get(2);
			
			System.out.println(cutsetWidth);
			System.out.println(aCutSetWidth);
			System.out.println(contextWidth);
			
		} catch (Exception e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		showTree();
		//propogate acutset, simplify leaf nodes by propogating cutsets
		//compute widths in the process
	}
	/**
	 * @param pCpt
	 * @return
	 */
	public boolean isExogenous(int pCpt) {
		Set gids = _context._context.getGIDs(pCpt);
		for( Object o : gids ) {
			String var = _context.getActualVarName((Integer)o);
			if( _context._alactionvars.contains(var) ) {
				return false;
			}
		}
		return true;
	}
	/**
	 * @param 
	 * @return
	 */
	private DTreeNode compose(List<DTreeNode> merges ) {
		ArrayList<DTreeNode> pList = new ArrayList<DTreeNode>(merges);
		
		while( pList.size() != 1 ) {
			DTreeNode one =  pList.remove(0);
			
			DTreeNode other =  pList.remove(0);
			
			DTreeNode newOne = new DTreeNode<RDDL2DD>(_context, one, other);
			_hmid2Node.put(newOne.id, newOne);
			pList.add(newOne);
		}
		return pList.get(0);
	}
	/**
	 * 
	 */
	private void showTree() {
		Graph g = new Graph(true, false, false, true);
		_root.toGraph(g);
		
		g.genFormatDotFile(VIEWER_FILE);
		
		DotViewer dv = new DotViewer() {

			public void nodeClicked(String name) {
				name = name.substring(1, name.length()-1);
//				System.out.println("Lookup: '" + name + "'");
				int id = Integer.parseInt(name);
				displayText(_hmid2Node .get(id).toString());
			}
		};
		dv.setWindowSizing(1024, 768, 0, 0, DEFAULT_VIEWER_TEXT_LINES * VIEWER_TEXT_HEIGHT);
		dv.showWindow(VIEWER_FILE);
		
	}

	public static void main(String[] args) {
		ADDHandler handler = new ADDHandler(DEBUG.PROBLEM_INFO, ORDER.INTERLEAVE);
		handler.buildFromFile(args[0], args[1]);
		
		new DTree<ADDHandler>(handler, new TreeSet<String>(handler.getAlnextstatevars()), handler.getMaxOrderString());
		
//		new DTree<ADDHandler>(handler, new TreeSet<String>(handler.getAlnextstatevars()), handler.getSumOrderString());
	}
}
